import { AxiosResponse } from 'axios'
import { DATA_REPORT_PATH } from '../Url'
import { ajaxDownloadFile, dragElement, postForOpenUrl } from '../Utils'
const LOADING_DIV_ID = '_loading_div_for_bask_text'
export const printFrameName = '_iframe_for_print_report'
export const saveReportFillMessage = '_save_report_fill_msg'
export const saveReportFillSuccess = '_save_report_fill_success_msg'
let needPrintReport = false
let printConfig: any = null
const SILENT_PRINT_DATA_KEY = 'basksoft.silent.print.data'

let silentPrintDialog: HTMLDivElement | null = null

const BaskReport = {
    doPrint: (config: ReportConfig) => {
        const conf: PrintConfig = {
            id: config.id,
            code: config.code,
            baseUrl: config.baseUrl,
            parameters: config.parameters,
            pageIndex: config.pageIndex,
            print: true,
            type: 'pdf'
        }
        process(conf)
    },
    doSlientPrint(config: ReportConfig) {
        const conf: SlientPrintConfig = {
            id: config.id,
            code: config.code,
            baseUrl: config.baseUrl,
            parameters: config.parameters,
            pageIndex: config.pageIndex,
            type: 'pdf'
        }
        processSilentPrint(conf)
    },
    doPreview(config: ReportConfig) {
        let url = config.baseUrl
        if (url.substring(url.length - 1) === '/') {
            url += DATA_REPORT_PATH + '/'
        } else {
            url += '/' + DATA_REPORT_PATH + '/'
        }
        if (config.id) {
            url += `view?file=${config.id}`
        } else {
            url += `view?code=${config.code}`
        }
        if (config.parameters) {
            url += `&parameters=${encodeURIComponent(JSON.stringify(config.parameters))}`
        }
        if (config.pageIndex) {
            url += `&pageIndex=${config.pageIndex}`
        }
        window.open(url)
    },
    doMultiPrint: (config: MultiReportConfig) => {
        const conf: MultiPrintReportConfig = {
            files: config.files,
            baseUrl: config.baseUrl,
            type: 'multipdf',
            print: true
        }
        process(conf)
    },
    doExportMultiExcel: (config: MultiReportConfig) => {
        const conf: MultiExportExcelReportConfig = {
            files: config.files,
            baseUrl: config.baseUrl,
            type: 'multiexcel'
        }
        process(conf)
    },
    doExportExcel(config: ReportConfig) {
        const conf: ExcelExportConfig = {
            id: config.id,
            code: config.code,
            baseUrl: config.baseUrl,
            parameters: config.parameters,
            pageIndex: config.pageIndex,
            type: 'excel'
        }
        process(conf)
    },
    doExportWord(config: ReportConfig) {
        const conf: WordExportConfig = {
            id: config.id,
            code: config.code,
            baseUrl: config.baseUrl,
            parameters: config.parameters,
            pageIndex: config.pageIndex,
            type: 'word'
        }
        process(conf)
    },
    doExportPdf(config: ReportConfig) {
        const conf: PdfExportConfig = {
            id: config.id,
            code: config.code,
            baseUrl: config.baseUrl,
            parameters: config.parameters,
            pageIndex: config.pageIndex,
            type: 'pdf'
        }
        process(conf)
    },
    doExportCsv(config: ReportConfig) {
        const conf: CsvExportConfig = {
            id: config.id,
            code: config.code,
            baseUrl: config.baseUrl,
            parameters: config.parameters,
            pageIndex: config.pageIndex,
            type: 'csv'
        }
        process(conf)
    },
    doExportMultiPdf(config: MultiReportConfig) {
        const conf: MultiPdfExportConfig = {
            files: config.files,
            baseUrl: config.baseUrl,
            type: 'multipdf',
            print: true
        }
        process(conf)
    }
}

function processSilentPrint(config: SlientPrintConfig) {
    let url = config.baseUrl
    if (url.substring(url.length - 1) === '/') {
        url += DATA_REPORT_PATH + '/'
    } else {
        url += '/' + DATA_REPORT_PATH + '/'
    }
    url += config.type
    if (config.id) {
        url += `?file=${config.id}`
    } else if (config.code) {
        url += `?code=${config.code}`
    } else {
        const tip = `导出【${config.type}】类型文件时必须指定文件id或code值`
        alert(tip)
        throw tip
    }
    if (config.tenantId) {
        url += `&tenantId=${config.tenantId}`
    }
    if (config.parameters) {
        url += `&parameters=${encodeURIComponent(JSON.stringify(config.parameters))}`
    }
    if (config.name) {
        url += `&_n=${encodeURIComponent(config.name)}`
    }
    if (config.pageIndex) {
        url += `&pageIndex=${config.pageIndex}`
    }
    url += `&online=true`
    //表示当前导出pdf操作后需要执行客户端静默打印
    url += `&silent=true`
    ajaxDownloadFile(url).then((res: AxiosResponse) => {
        const { data, headers } = res
        const blob = data.base64;
        const paper = headers['paper']
        if (!paper) {
            alert('无法从导出文件中获取文件信息,打印失败！')
            return
        }
        const json = JSON.parse(paper)
        const id = headers['id']
        const fileName = decodeURIComponent(headers['name'])
        const msg = {
            id: parseInt(id),
            name: fileName,
            paper: json.paper,
            width: json.w,
            height: json.h,
            marginLeft: json.lm,
            marginRight: json.rm,
            marginTop: json.tm,
            marginBottom: json.bm,
            copies: 1,
            duplex: false
        }
        const showDialogValue = loadSilentPrintDataFromLocalStorage('show', id)
        if (!showDialogValue) {
            showSilentPrintDialog(msg, blob)
        } else {
            const ip = loadSilentPrintDataFromLocalStorage('ip', id) || '127.0.0.1'
            const port = loadSilentPrintDataFromLocalStorage('port', id) || 56565
            sendMessageForSilentPrint(msg, blob, ip, port)
        }
    })
}

function process(config: any) {
    let op = '导出'
    if (config.print) {
        op = '打印'
    }
    if (!config.type) {
        alert(`${op}操作需要指定type属性以确定导出文件类型`)
        return
    }
    if (config.type !== 'multipdf' && config.type !== 'multiexcel' && !config.id && !config.code) {
        alert(`${op}操作需要指定报表id或code,或files属性值以确定具体的报表模版文件`)
        return
    }
    const types = ['excel', 'word', 'pdf', 'csv', 'multipdf', 'multiexcel']
    if (types.indexOf(config.type) === -1) {
        alert(
            `${op}文件类型type属性值只能是'excel','word','pdf','csv','multipdf','multiexcel',中一种`
        )
        return
    }
    const baseUrl = config.baseUrl
    if (!baseUrl) {
        alert(`需要指定报表服务器的URL`)
        return
    }
    let url = baseUrl
    if (url.substring(url.length - 1) === '/') {
        url += DATA_REPORT_PATH + '/print'
    } else {
        url += '/' + DATA_REPORT_PATH + '/print'
    }
    if (config.print) {
        showLoading()
        const iframe = getPrintFrame() as HTMLIFrameElement
        needPrintReport = true
        url += '?baseUrl='+encodeURIComponent(config.baseUrl);
        iframe.src = url
        printConfig = config
        if (printConfig.parameters) {
            printConfig.parameters = JSON.stringify(printConfig.parameters)
        } else if (printConfig.files) {
            printConfig.files = JSON.stringify(printConfig.files)
        }
        printConfig.printReport = true
    } else {
        doExport(config)
    }
}

function doExport(config: any) {
    let url = config.baseUrl
    if (url.substring(url.length - 1) === '/') {
        url += DATA_REPORT_PATH + '/'
    } else {
        url += '/' + DATA_REPORT_PATH + '/'
    }
    url += config.type
    let postData:any = {};
    if (config.type !== 'multipdf' && config.type !== 'multiexcel') {
        if (config.id) {
            postData.file = config.id
        } else if (config.code) {
            postData.code = config.code
        } else {
            const tip = `导出【${config.type}】类型文件时必须指定文件id值`
            alert(tip)
            throw tip
        }
        if (config.parameters) {
            postData.parameters = JSON.stringify(config.parameters)
        }
    } else {
        postData.files = JSON.stringify(config.files)
    }
    if (config.name) {
        postData._n = config.name
    }
    if (config.pageIndex) {
        postData.pageIndex = config.pageIndex
    }
    if (typeof(config.online) === 'undefined') {
        postData.online = true;
    } else {
        postData.online = config.online;
    }
    postForOpenUrl(url, postData, '_self');
}

function getPrintFrame() {
    const frames = document.getElementsByName(printFrameName)
    if (frames.length === 0) {
        return initPrintFrame()
    }
    return frames[0]
}

function initPrintFrame() {
    initMessageListener()
    const iframe = document.createElement('iframe')
    iframe.name = printFrameName
    iframe.style.width = '0'
    iframe.style.height = '0'
    iframe.style.border = 'none'
    iframe.onload = function (e: Event) {
        if (!needPrintReport) {
            return
        }
        needPrintReport = false
        const target = e.target as HTMLIFrameElement
        const targetWindow = target.contentWindow as Window
        setTimeout(() => {
            targetWindow.focus()
            targetWindow.postMessage(printConfig, '*')
        }, 1)
    }
    document.body.append(iframe)
    return iframe
}

function initMessageListener() {
    window.addEventListener('message', (event) => {
        const data = event.data
        if (data.doPrint) {
            hideLoading()
        }
    })
}

export type ReportConfig = {
    baseUrl: string
    parameters?: Record<string, any>
    pageIndex?: number
    id?: number
    code?: string
    tenantId?: string
    name?: string
}

export type FileConfig = {
    id: string
    code: string
    parameters?: Record<string, any>
}

export type MultiReportConfig = {
    baseUrl: string
    files: FileConfig[]
}

export type MultiPdfExportConfig = {
    baseUrl: string
    files: FileConfig[]
    type: 'multipdf'
    print: boolean
}

export type MultiExcelExportConfig = {
    baseUrl: string
    files: FileConfig[]
    type: 'multiexcel'
}

export type SlientPrintConfig = ReportConfig & {
    type: 'pdf'
}

export type PrintConfig = ReportConfig & {
    type: 'pdf'
    print: boolean
}
type ExcelExportConfig = ReportConfig & {
    type: 'excel'
}
type PdfExportConfig = ReportConfig & {
    type: 'pdf'
}
type WordExportConfig = ReportConfig & {
    type: 'word'
}
type CsvExportConfig = ReportConfig & {
    type: 'csv'
}

type MultiPrintReportConfig = ReportConfig & {
    type: 'multipdf'
    print: boolean
    baseUrl: string
    files: FileConfig[]
}
type MultiExportExcelReportConfig = {
    baseUrl: string
    type: 'multiexcel'
    files: FileConfig[]
}
export type ReportLink = {
    type: string;
    id: number;
    code: string;
    openType: 'page' | 'all';
    parameters: Record<string, any>;
    target: 'blank' | 'self' | 'dialog';
    targetWindowWidth: number;
    targetWindowHeight: number;
}

export type WebLink = {
    type: string;
    url: string;
    target: 'blank' | 'self' | 'dialog';
    targetWindowWidth: number;
    targetWindowHeight: number;
}

export type JSLink = {
    type: string;
    code: string;
    parameters: Record<string, any>;
}

export type ParameterLink = {
    type: string;
    parameters: Record<string, any>;
    target: 'blank' | 'self' | 'dialog';
    targetWindowWidth: number;
    targetWindowHeight: number;
}
function showSilentPrintDialog(printMsg: any, data: any) {
    if (silentPrintDialog) {
        silentPrintDialog.style.display = 'block'
        return
    }
    const dialogElement = document.createElement('div')
    document.body.append(dialogElement)
    silentPrintDialog = dialogElement
    dialogElement.style.display = 'block'
    dialogElement.style.position = 'fixed'
    dialogElement.style.zIndex = '800'
    dialogElement.style.left = '0'
    dialogElement.style.top = '0'
    dialogElement.style.width = '100%'
    dialogElement.style.height = '100%'
    dialogElement.style.color = 'rgb(58, 58, 58)'
    dialogElement.style.borderColor = 'rgba(221, 221, 221, 0.6)'
    const dialog = document.createElement('div')
    dialog.style.position = 'absolute'
    dialog.style.border = 'solid 1px #ccc'
    dialog.style.backgroundColor = 'white'
    dialog.style.boxShadow = '0px 0px 20px 0px #999'
    dialog.style.borderRadius = '2px'
    dialog.style.left = '50%'
    dialog.style.top = '50%'
    dialog.style.minWidth = '400px'
    dialog.style.transform = 'translate(-50%, -50%)'
    dialogElement.appendChild(dialog)
    const dialogHeader = document.createElement('div')
    dialogHeader.onmousedown = (e: MouseEvent) => {
        dragElement(e)
    }
    dialogHeader.style.padding = '15px 10px'
    dialogHeader.style.fontSize = '16px'
    dialogHeader.style.borderBottom = 'solid 1px #ccc'
    dialogHeader.style.height = '30px'
    dialogHeader.style.userSelect = 'none'
    dialogHeader.style.display = 'flex'
    dialog.appendChild(dialogHeader)
    const dialogTitle = document.createElement('span')
    dialogTitle.innerText = '无预览打印配置'
    dialogTitle.style.color = '#000'
    dialogTitle.style.fontSize = '22px'
    dialogTitle.style.fontWeight = '300'
    dialogTitle.style.margin = '0 20px 0 0'
    dialogTitle.style.whiteSpace = 'nowrap'
    dialogHeader.appendChild(dialogTitle)

    const dialogBody = document.createElement('div')
    dialogBody.style.padding = '15px 20px'
    dialogBody.style.fontSize = '13px'
    dialogBody.style.overflow = 'auto'
    dialog.appendChild(dialogBody)

    //构建dialog内容-------------------------------------

    const paperGroup = document.createElement('div');
    paperGroup.style.margin = '10px 0';
    paperGroup.style.padding = '5px';
    paperGroup.style.display = 'flex';
    dialogBody.appendChild(paperGroup);
    const paperLabel = document.createElement('label');
    paperLabel.innerText = `纸张类型：${printMsg.paper}，宽：${printMsg.width}mm，高：${printMsg.height}mm`;
    paperGroup.appendChild(paperLabel);

    const copiesGroup = document.createElement('div')
    copiesGroup.style.margin = '10px 0'
    copiesGroup.style.padding = '5px'
    copiesGroup.style.display = 'flex'
    dialogBody.appendChild(copiesGroup)
    const copiesLabel = document.createElement('label')
    copiesLabel.innerText = '打印份数：'
    copiesLabel.style.display = 'inline-block'
    copiesGroup.appendChild(copiesLabel)
    const copiesInput = document.createElement('input')
    copiesInput.type = 'number'
    copiesInput.style.flex = '1'
    copiesInput.value = printMsg.copies || 1
    copiesInput.onchange = () => {
        const value = copiesInput.value
        if (isNaN(Number(value))) {
            copiesInput.value = '1'
        }
        if (value === '') {
            copiesInput.value = '1'
        }
        if (Number(value) < 1) {
            copiesInput.value = '1'
        }
        printMsg.copies = parseInt(copiesInput.value)
    }
    copiesGroup.appendChild(copiesInput)

    const ipGroup = document.createElement('div')
    ipGroup.style.margin = '10px 0'
    ipGroup.style.padding = '5px'
    ipGroup.style.display = 'flex'
    dialogBody.appendChild(ipGroup)
    const ipLabel = document.createElement('label')
    ipLabel.innerText = '打印服务器IP：'
    ipLabel.style.display = 'inline-block'
    ipGroup.appendChild(ipLabel)
    const ipInput = document.createElement('input')
    ipInput.type = 'text'
    ipInput.style.flex = '1'
    ipInput.style.padding = '2px 5px'
    const fileId = printMsg.id
    let ip = loadSilentPrintDataFromLocalStorage('ip', fileId) || '127.0.0.1'
    ipInput.value = ip

    ipInput.onchange = () => {
        ip = ipInput.value
    }
    ipGroup.appendChild(ipInput)

    const portGroup = document.createElement('div')
    portGroup.style.margin = '10px 0'
    portGroup.style.padding = '5px'
    portGroup.style.display = 'flex'
    dialogBody.appendChild(portGroup)
    const portLabel = document.createElement('label')
    portLabel.innerText = '打印服务器端口号：'
    portLabel.style.display = 'inline-block'
    portGroup.appendChild(portLabel)
    const portInput = document.createElement('input')
    portInput.type = 'number'
    portInput.style.flex = '1'
    let port = loadSilentPrintDataFromLocalStorage('port', fileId) || `56565`
    portInput.value = port
    portInput.onchange = () => {
        if (isNaN(Number(port))) {
            portInput.value = '56565'
        }
        if (port === '') {
            portInput.value = '56565'
        }
        if (Number(port) < 1) {
            portInput.value = '56565'
        }
        port = portInput.value
    }
    portGroup.appendChild(portInput)
    dialogBody.appendChild(copiesGroup)

    const duplexGroup = document.createElement('div')
    dialogBody.appendChild(duplexGroup)
    duplexGroup.style.margin = '10px 0'
    duplexGroup.style.padding = '5px'
    duplexGroup.style.display = 'flex'

    const duplexInput = document.createElement('input')
    duplexInput.type = 'checkbox'
    duplexInput.checked = printMsg.duplex || false
    duplexInput.onchange = () => {
        printMsg.duplex = duplexInput.checked
    }
    duplexGroup.appendChild(duplexInput)
    const duplexLabel = document.createElement('label')
    duplexLabel.innerText = '双面打印（需要打印机支持）'
    duplexLabel.style.display = 'inline-block'
    duplexGroup.appendChild(duplexLabel)

    const showGroup = document.createElement('div')
    showGroup.style.margin = '10px 0'
    showGroup.style.padding = '5px'
    showGroup.style.display = 'flex'
    const showInput = document.createElement('input')
    showInput.type = 'checkbox'
    let show = loadSilentPrintDataFromLocalStorage('show', fileId) || false
    showInput.checked = show
    showGroup.appendChild(showInput)
    dialogBody.appendChild(showGroup)
    const showLabel = document.createElement('label')
    showLabel.innerText = '不再显示'
    showLabel.style.display = 'inline-block'
    showGroup.appendChild(showLabel)
    showInput.onchange = () => {
        show = showInput.checked
    }

    //构建dialog内容结束-------------------------------------

    const dialogFooter = document.createElement('div')
    dialogFooter.style.padding = '10px'
    dialogFooter.style.height = '28px'
    dialogFooter.style.borderTop = 'solid 1px #ccc'
    dialog.appendChild(dialogFooter)
    const footerButtonGroup = document.createElement('div')
    footerButtonGroup.style.display = 'flex'
    footerButtonGroup.style.justifyContent = 'flex-end'
    footerButtonGroup.style.gap = '10px'
    dialogFooter.appendChild(footerButtonGroup)
    const cancelButton = document.createElement('button')
    cancelButton.style.padding = '6px 12px'
    cancelButton.style.color = 'white'
    cancelButton.style.backgroundColor = '#6c757d'
    cancelButton.style.border = '1px solid #6c757d'
    cancelButton.style.borderRadius = '2px'
    cancelButton.style.cursor = 'pointer'
    cancelButton.style.transition =
        'color .15s ease-in-out, background-color .15s ease-in-out, border-color .15s ease-in-out, box-shadow .15s ease-in-out'
    cancelButton.innerText = '取消'
    cancelButton.onclick = () => {
        dialogElement.style.display = 'none'
    }
    footerButtonGroup.appendChild(cancelButton)

    const confirmButton = document.createElement('button')
    confirmButton.innerText = '确定'
    confirmButton.style.cursor = 'pointer'
    confirmButton.style.padding = '6px 12px'
    confirmButton.style.color = 'white'
    confirmButton.style.backgroundColor = '#212529'
    confirmButton.style.border = '1px solid #212529'
    confirmButton.style.borderRadius = '2px'
    confirmButton.style.transition =
        'color .15s ease-in-out, background-color .15s ease-in-out, border-color .15s ease-in-out, box-shadow .15s ease-in-out'
    footerButtonGroup.appendChild(confirmButton)
    confirmButton.onclick = () => {
        if (!ip || !port) {
            alert('请输入正确的IP和端口号')
            return
        }
        storeSilentPrintDataToLocalStorage('ip', ip, fileId)
        storeSilentPrintDataToLocalStorage('port', port, fileId)
        storeSilentPrintDataToLocalStorage('show', show, fileId)
        sendMessageForSilentPrint(printMsg, data, ip, Number(port))
        dialogElement.style.display = 'none'
    }
}

function loadSilentPrintDataFromLocalStorage(key: string, fileId: string) {
    const data = localStorage.getItem(SILENT_PRINT_DATA_KEY)
    if (!data) {
        return
    }
    const json = JSON.parse(data)
    if (!json[fileId]) {
        return
    }
    const fileData = json[fileId]
    if (fileData[key]) {
        return fileData[key]
    }
}

function storeSilentPrintDataToLocalStorage(key: string, value: string, fileId: string) {
    const data = localStorage.getItem(SILENT_PRINT_DATA_KEY)
    if (!data) {
        localStorage.setItem(SILENT_PRINT_DATA_KEY, JSON.stringify({ [fileId]: { [key]: value } }))
        return
    }
    const json = JSON.parse(data)
    if (!json[fileId]) {
        json[fileId] = { [key]: value }
    } else {
        json[fileId][key] = value
    }
    localStorage.setItem(SILENT_PRINT_DATA_KEY, JSON.stringify(json))
}

function sendMessageForSilentPrint(printMsg: any, data: any, ip: string, port: number) {
    showLoading()
    printMsg.data = data
    const msg = JSON.stringify(printMsg)
    const ws = new WebSocket(`ws://${ip}:${port}`)
    ws.onopen = () => {
        ws.send(msg)
        ws.close()
    }
    ws.onerror = () => {
        ws.close()
        alert('打印失败，请检查打印服务器是否正常启动')
        hideLoading()
    }
    ws.onclose = () => {
        hideLoading()
    }
}

function showLoading() {
    const loading = buildLoading()
    loading.style.display = 'block'
}

function hideLoading() {
    const loading = buildLoading()
    loading.style.display = 'none'
}

function buildLoading() {
    let loading = document.querySelector(`#${LOADING_DIV_ID}`) as HTMLDivElement
    if (loading) {
        return loading
    }
    const loadingStyle = document.createElement('style')
    const loadingContainerClassName = 'bask_text_loading_container_class_name'
    loadingStyle.innerHTML = `.${loadingContainerClassName} {
        position: fixed;
        display: none;
        top: 0;
        left: 0;
        width: 100%;
        height: 100%;
        background-color: #c7c7c780;
        z-index: 99999;
    }
    .bask-text-loading {
        position: absolute;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
        text-align: center;
    }
    .text-loading-circle {
        width: 40px;
        height: 40px;
        border-radius: 50%;
        border: 2px solid #111;
        border-top-color: transparent;
        animation: loading 1s linear infinite;
    }
    @keyframes loading {
        0% {
            transform: rotate(0deg);
        }
        100% {
            transform: rotate(360deg);
        }
    }`
    document.head.append(loadingStyle)
    loading = document.createElement('div')
    loading.id = LOADING_DIV_ID
    loading.className = loadingContainerClassName
    loading.innerHTML = `<div>
        <div class="bask-text-loading">
            <div class="text-loading-circle"></div>
            <div style="font-size:13px;color:#111">处理中...</div>
        </div>
    </div>`
    document.body.append(loading)
    return loading
}

export default BaskReport
